#include "ai-speech-recognition.h"
#include <functional>
#include <signal.h>
#include <unistd.h>

bool AISpeechRecognition::wakeState = false;

AISpeechRecognition::AISpeechRecognition(const string &audioDevice)
    : audioDevice(audioDevice),
      aiThread(nullptr),
      aiThreadRunFlag(false),
      barc(nullptr)
{
	float  audio_gain     = 1;
	bool   apply_frontend = false;
	string resourceFile   = "resources/common.res";
	/**
	 * 静音检测对象
	*/
	vad = new snowboy::SnowboyVad(resourceFile);
	vad->SetAudioGain(audio_gain);
	vad->ApplyFrontend(apply_frontend);

	//采样率
	printf("SampleRate:		%d\n", vad->SampleRate());
	//通道数
	printf("NumChannels:	%d\n", vad->NumChannels());
	//采样位
	printf("BitsPerSample:	%d\n", vad->BitsPerSample());

	/*
	* 热词检测对象
	*/
	string moduleFileList = "resources/models/mooc.pmdl";
	detect                = new snowboy::SnowboyDetect(resourceFile, moduleFileList);
	detect->SetSensitivity("0.5");
	detect->SetAudioGain(audio_gain);
	detect->ApplyFrontend(false);

	printf("Num hot words:%d\n", detect->NumHotwords());
	signal(SIGALRM, AISpeechRecognition::handleTimeOut);
}

bool AISpeechRecognition::start()
{
	/**
	 * 打开音频设备
	*/
	bool ok = alsaSound.open(audioDevice.c_str(), SND_PCM_STREAM_CAPTURE);
	if(!ok)
	{
		fprintf(stderr, "Fail to alsasound open %s\n", audioDevice.c_str());
		return false;
	}

	/**
	 * 设置音频参数
	*/
	pcm_hw_params_t parms = {
	    .access     = SND_PCM_ACCESS_RW_INTERLEAVED,
	    .format     = SND_PCM_FORMAT_S16_LE,
	    .channels   = 1,
	    .sampleRate = 16000,
	    .sampleBits = 16,
	    .frames     = 32,
	};

	ok = alsaSound.setParams(&parms);
	if(!ok)
	{
		fprintf(stderr, "Fail to alsasound set params\n");
		return false;
	}

	if(!barc)
	{
		barc        = new BaiduAiAsr("jE6Zt83Db5iTHm78PIAi4HUY", "jox6o5Vo5xkx0yypNWHRcdhosNio5IET");
		accessToken = barc->getAcessToken();
		if(accessToken.empty())
		{
			fprintf(stderr, "Fail to get acccess token\n");
			return false;
		}
	}

	/**
	 * 创建线程录制
	*/
	if(!aiThread)
	{
		aiThreadRunFlag = true;
		aiThread        = new thread(std::bind(&AISpeechRecognition::aiAudioThreadRun, this));
	}
	return ok;
}

void AISpeechRecognition::stop()
{
	aiThreadRunFlag = false;
}

void AISpeechRecognition::aiAudioThreadRun(void)
{
	uint32_t        time = 200;
	vector<uint8_t> audioData;
	while(aiThreadRunFlag)
	{
		//录音
		bool ok = alsaSound.record(time, audioData);
		if(!ok)
		{
			break;
		}
		//静音检测
		int ret = vad->RunVad((int16_t *)audioData.data(), audioData.size() / 2);
		// printf("run vad ret:%d\n", ret);
		if(ret < 0)
		{
			if(!userSpeechData.empty())
			{
				//暂停录音
				alsaSound.pause();
				//说完话了则识别
				recognitionUserSpeechData();
				//恢复录音
				alsaSound.resume();
			}
			continue;
		}

		// printf("Detect Non-silence\n");
		//如果用户在说话,则记录用户说话的数据,如果用户说完话，则识别
		userSpeechData.insert(userSpeechData.end(), audioData.begin(), audioData.end());
	}
}

/**
 * 用户声音识别
*/
void AISpeechRecognition::recognitionUserSpeechData(void)
{
	if(wakeState)
	{
		string audioText = barc->asrAudioData(accessToken, userSpeechData);
		cout << "AudioText : " << audioText << endl;
	}
	else
	{
		//唤醒检测
		int ret = detect->RunDetection((int16_t *)userSpeechData.data(), userSpeechData.size() / 2);
		// -2: Silence.
		// -1: Error.
		//  0: No event.
		//  1: Hotword 1 triggered.
		//  2: Hotword 2 triggered.
		printf("run RunDetection ret:%d\n", ret);
		if(ret > 0)
		{
			//播放音频
			playAckAudio();
			sleep(1);
			wakeState = true;
			alarm(10); //10s
		}
		//清空完毕
		userSpeechData.clear();
	}
}

void AISpeechRecognition::playAckAudio(void)
{
	srand(time(nullptr));
	int  num = rand() % 4 + 1;
	char playcmd[1024];
	sprintf(playcmd, "aplay resources/wav/%d.wav", num);
	system(playcmd);
}

void AISpeechRecognition::handleTimeOut(int signum)
{
	wakeState = false;
}
